package com.service;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dao.AttachmentDao;
import com.dao.CommentDao;
import com.dao.CommentsDao;
import com.dao.FieldsDao;
import com.dao.FixVersionsDao;
import com.dao.IssueDao;
import com.dao.IssueTypeDao;
import com.dao.PriorityDao;
import com.dao.ProjectCategoryDao;
import com.dao.ProjectDao;
import com.dao.ResolutionDao;
import com.dao.StatusDao;
import com.dao.SubtasksDao;
import com.dao.TimetrackingDao;
import com.dao.UserDao;
import com.dao.VersionsDao;
import com.dao.WatchersDao;
import com.dao.WorklogDao;
import com.dao.WorklogsDao;
import com.dto.AttachmentDTO;
import com.dto.CommentDTO;
import com.dto.CommentsDTO;
import com.dto.FieldsDTO;
import com.dto.FixVersionsDTO;
import com.dto.IssueDTO;
import com.dto.IssueTypeDTO;
import com.dto.PriorityDTO;
import com.dto.ProjectCategoryDTO;
import com.dto.ProjectDTO;
import com.dto.ResolutionDTO;
import com.dto.StatusDTO;
import com.dto.TimetrackingDTO;
import com.dto.UserDTO;
import com.dto.WatchersDTO;
import com.dto.WorklogDTO;
import com.dto.WorklogsDTO;
import com.entity.AttachmentEntity;
import com.entity.CommentEntity;
import com.entity.CommentsEntity;
import com.entity.FieldsEntity;
import com.entity.FixVersionsEntity;
import com.entity.IssueEntity;
import com.entity.IssueTypeEntity;
import com.entity.PriorityEntity;
import com.entity.ProjectCategoryEntity;
import com.entity.ProjectEntity;
import com.entity.ResolutionEntity;
import com.entity.StatusEntity;
import com.entity.SubtasksEntity;
import com.entity.TimetrackingEntity;
import com.entity.UserEntity;
import com.entity.WatchersEntity;
import com.entity.WorklogEntity;
import com.entity.WorklogsEntity;

@Service
public class DatabaseService {
	@Autowired
	private AttachmentDao attachmentDao;
	@Autowired
	private CommentDao commentDao;
	@Autowired
	private CommentsDao commentsDao;
	@Autowired
	private FieldsDao fieldsDao;
	@Autowired
	private FixVersionsDao fixVersionsDao;
	@Autowired
	private IssueDao issueDao;
	@Autowired
	private IssueTypeDao issueTypeDao;
	@Autowired
	private PriorityDao priorityDao;
	@Autowired
	private ProjectCategoryDao projectCategoryDao;
	@Autowired
	private ProjectDao projectDao;
	@Autowired
	private ResolutionDao resolutionDao;
	@Autowired
	private StatusDao statusDao;
	@Autowired
	private SubtasksDao subtasksDao;
	@Autowired
	private TimetrackingDao timetrackingDao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private VersionsDao versionsDao;
	@Autowired
	private WorklogDao worklogDao;
	@Autowired
	private WorklogsDao worklogsDao;
	@Autowired
	private WatchersDao watchersDao;

	@Transactional
	public IssueEntity issueIntoEntity(IssueDTO issue) {
		if (issue != null) {
			IssueEntity entity = issueDao.getIssueByUniqueId(issue.getId());

			IssueEntity issueEntity = new IssueEntity();
			issueEntity.setId(issue.getId());
			issueEntity.setKeyIssue(issue.getKey());
			issueEntity.setSelf(issue.getSelf());
			issueEntity.setFieldsEntity(fieldsIntoEntity(issue));
			if (entity != null) {
				issueEntity.setIdIssue(entity.getIdIssue());
				issueDao.update(issueEntity);
			} else {
				issueDao.save(issueEntity);
			}
			worklogsIntoEntity(issue);
			commentsIntoEntity(issue);
			attachmentIntoEntity(issue);
			fixVersionsIntoEntity(issue);
			watchersIntoEntity(issue, issueEntity);
			subtasksIntoEntity(issue, issueEntity.getFieldsEntity());
			return issueEntity;
		}
		return null;
	}

	@Transactional
	public FieldsEntity fieldsIntoEntity(IssueDTO issue) {

		FieldsDTO fields = issue.getFields();

		FieldsEntity fieldsEntity = new FieldsEntity();
		fieldsEntity.setCommentEntity(commentIntoEntity(issue));
		fieldsEntity.setCreated(fields.getCreated());
		fieldsEntity.setDescription(fields.getDescription());
		fieldsEntity.setDuedate(fields.getDuedate());
		fieldsEntity.setTimespent(fields.getTimespent());
		fieldsEntity.setIssueTypeEntity(issueTypeIntoEntity(fields.getIssuetype()));
		fieldsEntity.setPriorityEntity(priorityIntoEntity(fields.getPriority()));
		fieldsEntity.setProjectEntity(projectIntoEntity(fields.getProject()));
		fieldsEntity.setResolutionDate(fields.getResolutionDate());
		fieldsEntity.setResolutionEntity(resolutionIntoEntity(fields.getResolution()));
		fieldsEntity.setStatusEntity(statusIntoEntity(fields.getStatus()));
		fieldsEntity.setSummary(fields.getSummary());
		fieldsEntity.setTimetrackingEntity(timetrackingIntoEntity(issue));
		fieldsEntity.setUpdated(fields.getUpdated());
		fieldsEntity.setUserEntityByIdAuthor(userIntoEntity(fields.getAssignee()));
		fieldsEntity.setUserEntityByIdReporter(userIntoEntity(fields.getReporter()));
		fieldsEntity.setWorklogEntity(worklogIntoEntity(issue));
		fieldsEntity.setIssueEntity(issueIntoEntity(fields.getParent()));

		IssueEntity issueEntity = issueDao.getIssueByUniqueId(issue.getId());
		boolean exists = true;
		if (issueEntity != null) {
			FieldsEntity entity = issueEntity.getFieldsEntity();
			if (entity != null) {
				fieldsEntity.setIdFields(entity.getIdFields());
				fieldsDao.update(fieldsEntity);
			} else {
				exists = false;
			}
		} else {
			exists = false;
		}
		if (!exists) {
			fieldsDao.save(fieldsEntity);
		}
		return fieldsEntity;
	}

	@Transactional
	public void fixVersionsIntoEntity(IssueDTO issue) {
		FieldsDTO fields = issue.getFields();
		FixVersionsDTO[] fixs = fields.getFixVersions();
		if (fixs != null) {
			for (FixVersionsDTO fixVersions : fixs) {
				FixVersionsEntity entity = fixVersionsDao.getFixVersionsByUniqueId(fixVersions.getId());
				FixVersionsEntity fixVersionsEntity = new FixVersionsEntity();
				fixVersionsEntity.setArchived(fixVersions.getArchived());
				fixVersionsEntity.setDescription(fixVersions.getDescription());
				fixVersionsEntity.setFieldsEntity(fieldsIntoEntity(issue));
				fixVersionsEntity.setId(fixVersions.getId());
				fixVersionsEntity.setName(fixVersions.getName());
				fixVersionsEntity.setReleased(fixVersions.getReleased());
				fixVersionsEntity.setSelf(fixVersions.getSelf());
				if (entity != null) {
					fixVersionsEntity.setIdFixVersions(entity.getIdFixVersions());
					fixVersionsDao.update(fixVersionsEntity);
				} else {
					fixVersionsDao.save(fixVersionsEntity);
				}

			}
		}
	}

	@Transactional
	public IssueTypeEntity issueTypeIntoEntity(IssueTypeDTO issueType) {

		IssueTypeEntity entity = issueTypeDao.getIssueTypeByUniqueId(issueType.getId());

		IssueTypeEntity issueTypeEntity = new IssueTypeEntity();
		issueTypeEntity.setDescription(issueType.getDescription());
		issueTypeEntity.setId(issueType.getId());
		issueTypeEntity.setName(issueType.getName());
		issueTypeEntity.setSelf(issueType.getSelf());
		issueTypeEntity.setSubtask(issueType.getSubtask());
		if (entity != null) {
			issueTypeEntity.setIdIssueType(entity.getIdIssueType());
			issueTypeDao.update(issueTypeEntity);
		} else {
			issueTypeDao.save(issueTypeEntity);
		}
		return issueTypeEntity;
	}

	@Transactional
	public Object watchersIntoEntity(IssueDTO issue, IssueEntity issueEntity) {
		WatchersDTO watchersDto = issue.getWatchers();
		if (watchersDto != null) {
			UserDTO[] watchers = watchersDto.getWatchers();
			Set<UserEntity> userSet = new HashSet<UserEntity>();
			WatchersEntity watchersEntity;
			for (UserDTO watcher : watchers) {
				UserEntity user = userIntoEntity(watcher);
				userSet.add(user);
			}
			Set<WatchersEntity> watchersSet = issueEntity.getWatchersEntities();
			if (watchersSet != null) {
				Iterator<WatchersEntity> iter = watchersSet.iterator();
				if (iter.hasNext()) {
					watchersEntity = iter.next();
					watchersEntity.setIssueEntity(issueEntity);
					watchersEntity.setUserEntities(userSet);
					watchersDao.update(watchersEntity);
					return null;
				}
			}
			watchersEntity = new WatchersEntity();
			watchersEntity.setIssueEntity(issueEntity);
			watchersEntity.setUserEntities(userSet);
			watchersDao.save(watchersEntity);
		}
		return null;

	}

	// TODO to be done
	@Transactional
	public Object subtasksIntoEntity(IssueDTO issue, FieldsEntity fieldsEntity) {
		SubtasksEntity subtasksEntity;
		FieldsDTO fields = issue.getFields();
		IssueDTO[] subtasks = fields.getSubtasks();
		if (subtasks != null) {
			Set<IssueEntity> setIssues = new HashSet<IssueEntity>();

			for (IssueDTO subtask : subtasks) {
				IssueEntity issueEntity = issueIntoEntity(subtask);
				setIssues.add(issueEntity);
			}
			Set<SubtasksEntity> subtasksSet = fieldsEntity.getSubtasksEntities();
			if (subtasksSet != null) {
				Iterator<SubtasksEntity> iter = subtasksSet.iterator();
				if (iter.hasNext()) {
					subtasksEntity = iter.next();
					subtasksEntity.setFieldsEntity(fieldsEntity);
					subtasksEntity.setIssueEntities(setIssues);
					subtasksDao.update(subtasksEntity);
					return null;
				}
				subtasksEntity = new SubtasksEntity();
				subtasksEntity.setFieldsEntity(fieldsEntity);
				subtasksEntity.setIssueEntities(setIssues);
				subtasksDao.save(subtasksEntity);
			}
		}
		return null;
	}

	@Transactional
	public void worklogsIntoEntity(IssueDTO issue) {
		FieldsDTO fields = issue.getFields();
		WorklogDTO worlog = fields.getWorklog();
		if (worlog != null) {
			WorklogsDTO[] worlogs = worlog.getWorklogs();
			for (WorklogsDTO worklog : worlogs) {
				WorklogsEntity entity = worklogsDao.getWorklogsByUniqueId(worklog.getId());

				WorklogsEntity worklogsEntity = new WorklogsEntity();
				worklogsEntity.setComment(worklog.getComment());
				worklogsEntity.setCreated(worklog.getCreated());
				worklogsEntity.setId(worklog.getId());
				worklogsEntity.setSelf(worklog.getSelf());
				worklogsEntity.setStarted(worklog.getStarted());
				worklogsEntity.setTimeSpent(worklog.getTimeSpent());
				worklogsEntity.setTimeSpentSeconds(worklog.getTimeSpentSeconds());
				worklogsEntity.setUpdated(worklog.getUpdated());
				worklogsEntity.setWorklogEntity(worklogIntoEntity(issue));
				worklogsEntity.setUserEntityByIdAuthor(userIntoEntity(worklog.getAuthor()));
				worklogsEntity.setUserEntityByIdUpdatedAuthor(userIntoEntity(worklog.getUpdateAuthor()));
				if (entity != null) {
					worklogsEntity.setIdWorklogs(entity.getIdWorklogs());
					worklogsDao.update(worklogsEntity);
				} else {
					worklogsDao.save(worklogsEntity);
				}
			}
		}
	}

	// TODO add new raw in database when new comment appears(compare updated and
	// created fields)

	@Transactional
	public void commentsIntoEntity(IssueDTO issue) {
		CommentDTO com = issue.getFields().getComment();
		if (com != null) {
			CommentsDTO[] comments = com.getComments();
			for (CommentsDTO comm : comments) {
				CommentsEntity entity = commentsDao.getCommentByUniqueId(comm.getId());

				CommentsEntity commentsEntity = new CommentsEntity();
				commentsEntity = new CommentsEntity();
				commentsEntity.setBody(comm.getBody());
				commentsEntity.setCommentEntity(commentIntoEntity(issue));
				commentsEntity.setCreated(comm.getCreated());
				commentsEntity.setId(comm.getId());
				commentsEntity.setSelf(comm.getSelf());
				commentsEntity.setUpdated(comm.getUpdated());
				commentsEntity.setUserEntityByIdAuthor(userIntoEntity(comm.getAuthor()));
				commentsEntity.setUserEntityByIdUpdateAuthor(userIntoEntity(comm.getUpdateAuthor()));
				if (entity != null) {
					commentsEntity.setIdComments(entity.getIdComments());
					commentsDao.update(commentsEntity);
				} else {
					commentsDao.save(commentsEntity);
				}
			}
		}
	}

	@Transactional
	public CommentEntity commentIntoEntity(IssueDTO issue) {

		if (issue.getFields().getComment() != null) {

			String maxResults = issue.getFields().getComment().getMaxResults();

			IssueEntity issueEntity = issueDao.getIssueByUniqueId(issue.getId());

			CommentEntity commentEntity = new CommentEntity();
			commentEntity.setMaxResults(maxResults);
			boolean exists = true;
			if (issueEntity != null) {
				FieldsEntity fieldsEntity = issueEntity.getFieldsEntity();
				if (fieldsEntity != null) {
					CommentEntity entity = fieldsEntity.getCommentEntity();
					if (entity != null) {
						commentEntity.setMaxResults(maxResults);
						commentDao.update(commentEntity);
					} else {
						exists = false;
					}
				} else {
					exists = false;
				}
			} else {
				exists = false;
			}
			if (!exists) {
				commentDao.save(commentEntity);
			}
			return commentEntity;
		}
		return null;
	}

	@Transactional
	public PriorityEntity priorityIntoEntity(PriorityDTO priority) {

		PriorityEntity entity = priorityDao.getPriorityByUniqueId(priority.getId());

		PriorityEntity priorityEntity = new PriorityEntity();
		priorityEntity.setId(priority.getId());
		priorityEntity.setName(priority.getName());
		if (entity != null) {
			priorityEntity.setIdPriority(entity.getIdPriority());
			priorityDao.update(priorityEntity);
		} else {
			priorityDao.save(priorityEntity);
		}
		return priorityEntity;
	}

	@Transactional
	public UserEntity userIntoEntity(UserDTO user) {

		if (user != null) {
			UserEntity userEntity = userDao.getUserByEmail(user.getEmailAddress());

			if (userEntity != null) {
				return userEntity;
			}

			userEntity = new UserEntity();
			userEntity.setActive(user.getActive());
			userEntity.setDisplayName(user.getDisplayName());
			userEntity.setEmailAddress(user.getEmailAddress());
			userEntity.setName(user.getName());
			userEntity.setSelf(user.getSelf());
			userDao.save(userEntity);
			return userEntity;
		}
		return null;
	}

	@Transactional
	public WorklogEntity worklogIntoEntity(IssueDTO issue) {
		WorklogDTO worklog = issue.getFields().getWorklog();
		if (worklog != null) {
			IssueEntity issueEntity = issueDao.getIssueByUniqueId(issue.getId());
			WorklogEntity worklogEntity = new WorklogEntity();
			worklogEntity.setMaxResults(worklog.getMaxResults());
			worklogEntity.setStartAt(worklog.getStartAt());
			worklogEntity.setTotal(worklog.getTotal());
			boolean exists = true;
			if (issueEntity != null) {
				FieldsEntity fieldsEntity = issueEntity.getFieldsEntity();
				if (fieldsEntity != null) {
					WorklogEntity entity = fieldsEntity.getWorklogEntity();
					if (entity != null) {
						worklogEntity.setIdWorklog(entity.getIdWorklog());
						worklogDao.update(worklogEntity);
					} else {
						exists = false;
					}
				} else {
					exists = false;
				}
			} else {
				exists = false;
			}
			if (!exists) {
				worklogDao.save(worklogEntity);
			}
			return worklogEntity;
		}
		return null;
	}

	@Transactional
	public TimetrackingEntity timetrackingIntoEntity(IssueDTO issue) {
		TimetrackingDTO timetracking = issue.getFields().getTimetracking();
		if (timetracking != null) {
			IssueEntity issueEntity = issueDao.getIssueByUniqueId(issue.getId());

			TimetrackingEntity timetrackingEntity = new TimetrackingEntity();
			timetrackingEntity.setRemainingEstimate(timetracking.getRemainingEstimate());
			timetrackingEntity.setRemainingEstimateSeconds(timetracking.getRemainingEstimateSeconds());
			timetrackingEntity.setTimeSpent(timetracking.getTimeSpent());
			timetrackingEntity.setTimeSpentSeconds(timetracking.getTimeSpentSeconds());
			boolean exists = true;
			if (issueEntity != null) {
				FieldsEntity fieldsEntity = issueEntity.getFieldsEntity();
				if (fieldsEntity != null) {
					TimetrackingEntity entity = fieldsEntity.getTimetrackingEntity();
					if (entity != null) {
						timetrackingEntity.setIdTimetracking(entity.getIdTimetracking());
						timetrackingDao.update(timetrackingEntity);
					} else {
						exists = false;
					}
				} else {
					exists = false;
				}
			} else {
				exists = false;
			}
			if (!exists) {
				timetrackingDao.save(timetrackingEntity);
			}
			return timetrackingEntity;
		}
		return null;
	}

	@Transactional
	public ProjectCategoryEntity projectCategoryIntoEntity(ProjectCategoryDTO projectCategory) {

		ProjectCategoryEntity entity = projectCategoryDao.getProjectCategoryByUniqueId(projectCategory.getId());
		ProjectCategoryEntity projectCategoryEntity = new ProjectCategoryEntity();
		projectCategoryEntity.setId(projectCategory.getId());
		projectCategoryEntity.setDescription(projectCategory.getDescription());
		projectCategoryEntity.setName(projectCategory.getName());
		projectCategoryEntity.setSelf(projectCategory.getSelf());

		if (entity != null) {
			projectCategoryEntity.setIdProjectCategory(entity.getIdProjectCategory());
			projectCategoryDao.update(projectCategoryEntity);
		} else {
			projectCategoryDao.save(projectCategoryEntity);
		}
		return projectCategoryEntity;
	}

	@Transactional
	public ProjectEntity projectIntoEntity(ProjectDTO project) {
		if (project != null) {
			ProjectEntity entity = projectDao.getProjectByUniqueId(project.getId());

			ProjectEntity projectEntity = new ProjectEntity();
			projectEntity.setKeyProject(project.getKey());
			projectEntity.setName(project.getName());
			projectEntity.setSelf(project.getSelf());
			projectEntity.setId(project.getId());
			if (project.getProjectCategory() != null) {
				projectEntity.setProjectCategoryEntity(projectCategoryIntoEntity(project.getProjectCategory()));
			}
			if (entity != null) {
				projectEntity.setIdProject(entity.getIdProject());
				projectDao.update(projectEntity);
			} else {
				projectDao.save(projectEntity);
			}
			return projectEntity;
		}
		return null;
	}

	@Transactional
	public ResolutionEntity resolutionIntoEntity(ResolutionDTO resolution) {

		if (resolution != null) {

			ResolutionEntity entity = resolutionDao.getResolutionByUniqueId(resolution.getId());

			ResolutionEntity resolutionEntity = new ResolutionEntity();
			resolutionEntity.setId(resolution.getId());
			resolutionEntity.setDescription(resolution.getDescription());
			resolutionEntity.setName(resolution.getName());
			resolutionEntity.setSelf(resolution.getSelf());
			if (entity != null) {
				resolutionEntity.setIdResolution(entity.getIdResolution());
				resolutionDao.update(resolutionEntity);
			} else {
				resolutionDao.save(resolutionEntity);
			}
			return resolutionEntity;
		}
		return null;
	}

	@Transactional
	public StatusEntity statusIntoEntity(StatusDTO status) {

		StatusEntity entity = statusDao.getStatusByUniqueId(status.getId());
		StatusEntity statusEntity = new StatusEntity();
		statusEntity.setId(status.getId());
		statusEntity.setDescription(status.getDescription());
		statusEntity.setName(status.getName());
		if (entity != null) {
			statusEntity.setIdStatus(entity.getIdStatus());
			statusDao.update(statusEntity);
		} else {
			statusDao.save(statusEntity);
		}
		return statusEntity;
	}

	@Transactional
	public void attachmentIntoEntity(IssueDTO issue) {
		FieldsDTO fields = issue.getFields();
		AttachmentDTO[] attachments = fields.getAttachment();
		if (attachments != null) {
			for (AttachmentDTO attachment : attachments) {
				AttachmentEntity attachmentEntity = new AttachmentEntity();
				attachmentEntity.setId(attachment.getId());
				attachmentEntity.setContent(attachment.getContent());
				attachmentEntity.setCreated(attachment.getCreated());
				attachmentEntity.setFilename(attachment.getFilename());
				attachmentEntity.setMimeType(attachment.getMimeType());
				attachmentEntity.setSelf(attachment.getSelf());
				attachmentEntity.setSize(attachment.getSize());
				attachmentEntity.setUserEntity(userIntoEntity(attachment.getAuthor()));
				attachmentEntity.setFieldsEntity(fieldsIntoEntity(issue));
				AttachmentEntity entity = attachmentDao.getAttachmentByUniqueId(attachment.getId());
				if (entity != null) {
					attachmentEntity.setIdAttachment(entity.getIdAttachment());
					attachmentDao.update(attachmentEntity);
				} else {
					attachmentDao.save(attachmentEntity);
				}
			}
		}
	}
}
